package org.naxx.security.parser;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import org.naxx.security.common.Decision;
import org.naxx.security.expression.ExpressionTree;
import org.naxx.security.model.Rule;
import org.naxx.security.model.Target;
import org.naxx.security.model.impl.ConditionImpl;
import org.naxx.security.model.impl.RuleImpl;
import org.naxx.security.parser.util.QNames;

public class RuleParser extends AbstractXmlParser<Rule> {
	
	private TargetParser targetParser;
	private ApplyParser applyParser;
	
	public void setTargetParser(TargetParser targetParser) {
		this.targetParser = targetParser;
	}
	public void setApplyParser(ApplyParser applyParser) {
		this.applyParser = applyParser;
	}

	/**
	 * Precondition: Cursor points to element just before opening Rule element.
	 * Postcondition: Cursor points to closing Rule element.
	 */
	public Rule parse(XMLEventReader reader) throws Exception {
		final RuleImpl rule = new RuleImpl();
		XMLEvent event = reader.nextTag(); // now at opening Rule element
		StartElement start = event.asStartElement();
		Attribute ruleId = start.getAttributeByName(QNames.RULE_ID_ATTRIBUTE);
		Attribute effect = start.getAttributeByName(QNames.EFFECT_ATTRIBUTE);
		rule.setEffect(Decision.valueOf(effect.getValue().toUpperCase()));
		rule.setId(ruleId.getValue());
		
		event = reader.nextTag();
		while(!event.isEndElement()) { // until end Rule element
			start = event.asStartElement();
			String localPart = start.getName().getLocalPart();
			if("Description".equals(localPart)) {
				StringBuilder buffer = new StringBuilder();
				event = this.getCharacters(reader, buffer);
				rule.setDescription(buffer.toString().trim());
			}
			else if("Target".equals(localPart)) {
				Target target = this.targetParser.parse(reader);
				rule.setTarget(target);
			}
			else if("Condition".equals(localPart)) {
				ExpressionTree expressionTree = this.applyParser.parse(reader);
				ConditionImpl condition = new ConditionImpl(expressionTree);
				rule.setCondition(condition);
				event = reader.nextEvent(); // now at closing Condition element
			}
			event = reader.nextTag();
		}
		return rule;
	}
}
